package tcplib

import (
	"fmt"
	"net"
	"sync"
)

type TcpServer struct {
	host     string         // 主机地址
	port     int            // 主机端口
	listener net.Listener   // 监听
	wait     sync.WaitGroup // 等待信号量
	quit     chan struct{}  // 退出信号
	handler  SessionHandler // 会话回调
	sessions sync.Map       // 保存全部会话
}

// 启动TCP服务线程
func StartTcpServer(host string, port int, handler SessionHandler) *TcpServer {
	fmt.Println("TcpServer:", host, port)
	s := TcpServer{
		host:    host,
		port:    port,
		handler: handler,
		quit:    make(chan struct{}),
	}
	addr := host + ":" + fmt.Sprint(port)
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		fmt.Println(err)
		return nil
	}
	s.listener = listener
	s.wait.Add(1)
	go func() {
		defer s.wait.Done()
		s.service()
	}()
	return &s
}

// 关闭服务
func (s *TcpServer) Stop() {
	// 退出服务
	close(s.quit)
	// 停止监听
	s.listener.Close()
	// 主动退出会话
	s.sessions.Range(func(key, value interface{}) bool {
		session, ok := value.(*TcpSession)
		if ok {
			session.Stop()
		}
		return true
	})
	// 等待服务退出
	s.wait.Wait()
}

// 会话新建回调，保存会话
func (s *TcpServer) TcpSessionCreated(session *TcpSession) bool {
	s.sessions.Store(session.conn.RemoteAddr().String(), session)
	s.handler.TcpSessionCreated(session)
	return true
}

// 会话关闭回调，删除会话
func (s *TcpServer) TcpSessionClosed(session *TcpSession) {
	s.sessions.Delete(session.conn.RemoteAddr().String())
	s.handler.TcpSessionClosed(session)
}

// 会话数据回调
func (s *TcpServer) TcpSessionReceived(session *TcpSession, data []byte) bool {
	s.handler.TcpSessionReceived(session, data)
	return true
}

// TCP服务监听线程
// 关闭服务，首先需要close quit通道，然后调用Close()方法
func (s *TcpServer) service() {
	for {
		conn, err := s.listener.Accept()
		if err != nil {
			select {
			// 收到quit信号，表示主动退出，不打印log
			case <-s.quit:
				return
			default:
				fmt.Println("accept error", err)
				return
			}
		} else {
			// 新建会话
			session := TcpSessionStart(conn, s)
			if session == nil {
				conn.Close()
				return
			}
		}
	}
}
